package dipl.algorithm.test.compare;

import dipl.algorithm.impl.Parameters;
import dipl.algorithm.impl.ScmpAlgorithmBezierRootIsolation;
import dipl.algorithm.math.curve.BezierCurve;
import dipl.algorithm.math.utility.BezierCurveFactory;
import dipl.algorithm.statistics.Statistics;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Random;
import org.apfloat.Apfloat;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

/**
 * @author Marko Walther
 * Tests measure running time of root-isolation algorithm on random inputs
 */
@RunWith(Parameterized.class)
public class MeasureRTRootIsolationRandom {

	public MeasureRTRootIsolationRandom( int degree ) {
		this.degree = degree;
	}

	@BeforeClass
	public static void setUpClass() throws Exception {
		run 				= 0;
		runsPerData = 500; // number of runs per degree
		treshold		= new Apfloat( 1e-4, 48, 2 ); // emergency stop treshold

		int numData = Data().size();
		meanRT = new double[numData];
	}

	@AfterClass
	public static void tearDownClass() throws Exception {
		// create and open html file
		String outDir = "statistics/comparison/results/rootiso_nscmp_random/";
		if( new File( outDir ).exists() == false )
			new File( outDir ).mkdirs();
			SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd_HH-mm-ss" );
		File file = new File( outDir+format.format( new Date() )+".html" );
		BufferedWriter writer = new BufferedWriter( new FileWriter( file ) );

		writer.write( "<html><head><style type=\"text/css\">p,td,th { font-size:small;}</style></head><body>" );
		writer.write( "<h3>Laufzeit des Nullstellenisolations-Verfahrens durch Subdivision mit zufälligen Eingaben<br>ohne Superkomposition.</h3>" );
		writer.write( "<p>Testläufe je Kurvengrad: <b>"+runsPerData+"</b> Anwendungsschranke: <b>"+treshold.doubleValue()+"</b></p>" );

		writer.write( "<p><b>Ergebnisse:</b></p>" );
		writer.write( "<table border=\"1\">" );
		Object[][] data = (Object[][])Data().toArray();
		writer.write( "<thead><tr>" );
		writer.write( "<th><b>Grad:</b></th>" );
		writer.write( "<th><b>Laufzeit (in s):</b></th>" );
		writer.write( "</tr></thead>" );
		writer.write( "<tbody>" );
		DecimalFormat df4 = new DecimalFormat( "0.0000" );
		for( int i = 0; i < data.length; i++ ) {
			writer.write( "<tr>" );
			writer.write( "<td>"+(Integer)data[i][0]+"</td>" );
			writer.write( "<td>"+df4.format( meanRT[i] )+"s</td>" );
			writer.write( "</tr>" );
		}
		writer.write( "</tbody>" );
		writer.write( "</table>" );
		writer.write( "</body></html>" );
		writer.close();
	}

	//
	// PARAMETERS
	//

 	@Parameterized.Parameters
 	public static Collection<Object[]> Data() {
 		// return curve degrees
		return Arrays.asList( new Object[][] {
			{ Integer.valueOf( 1 ) },
			{ Integer.valueOf( 2 ) },
			{ Integer.valueOf( 3 ) },
			{ Integer.valueOf( 4 ) },
			{ Integer.valueOf( 5 ) },
			{ Integer.valueOf( 6 ) },
			{ Integer.valueOf( 7 ) },
			{ Integer.valueOf( 8 ) },
			{ Integer.valueOf( 9 ) },
			{ Integer.valueOf( 10 ) },
			{ Integer.valueOf( 11 ) },
			{ Integer.valueOf( 12 ) },
			{ Integer.valueOf( 13 ) },
			{ Integer.valueOf( 14 ) },
			{ Integer.valueOf( 15 ) },
			{ Integer.valueOf( 16 ) },
			{ Integer.valueOf( 17 ) },
			{ Integer.valueOf( 18 ) },
			{ Integer.valueOf( 19 ) },
			{ Integer.valueOf( 20 ) },
		});
 	}

	//
	// MEASURE METHODS
	//

	/**
	 * Measurement
	 */
	@Test
	public void Measure() {
		// parameters
		// collect results
		Statistics[] res  = new Statistics[runsPerData]; // statistical results with supercomposition method
		Random rand = new Random();
		ScmpAlgorithmBezierRootIsolation alg = new ScmpAlgorithmBezierRootIsolation(); // algorithm

		try {
			// generate random input curves

			BezierCurve[] curve = new BezierCurve[runsPerData];
			for( int i = 0; i < runsPerData; i++ ) {
				curve[i] = BezierCurveFactory.CreateRandomBernsteinPolynomialIC( rand, degree, 0, -50, 50 );
			}

			// start with supercomp.
			for( int i = 0; i < runsPerData; i++ ) {
				alg.CalculateIntersections( curve[i], Parameters.COLLECT_DATA, treshold, 0 );
				res[i] = alg.Statistics();
			}

			// compare statistical results
			meanRT[run] = 0.0;
			for( int i = 0; i < runsPerData; i++ ) {
				Statistics s = res[i];
				meanRT[run] += (double)(s.endTimeMS-s.startTimeMS)/1000.0;
			}
			meanRT[run] /= (double)runsPerData;

		}
		catch( Exception e) {
			e.printStackTrace();
			Assert.fail();
		}
		run++;
	}

	//
	// MEMBERS
	//

	/** curve degree */
	int degree;

	/** current run */
	static int run;

	/** number of runs per degree */
	static int runsPerData;

	/** emergenzy treshold */
	static Apfloat treshold;

	/** mean running-times per degree */
	static double[] meanRT;

}